home *** CD-ROM | disk | FTP | other *** search
/ AOL File Library: 4,401 to 4,500 / aol-file-protocol-4400-4401-to-4500.zip / AOLDLs / PDA-Newton Development / ND+ NewtonScript ByteCode / bytcd.txt next >
Text File  |  2014-12-08  |  27KB  |  862 lines

  1. NewtonScript ByteCode
  2.  
  3. Matthew Faupel
  4.  
  5. Draft 1
  6.  
  7. 17 Nov 1994
  8.  
  9. Contents
  10.  
  11. 1    Background to ByteCode        2
  12.  
  13. 1.1    The Representation of Compiled NewtonScript        2
  14.  
  15. 1.2    How Values are Encoded in NewtonScript        3
  16.  
  17. 2    ByteCode        4
  18.  
  19. 2.1    The General Format of ByteCode        4
  20.  
  21. 2.2    Explanation of the Description of Individual ByteCodes        4
  22.  
  23. 2.3    ByteCode Descriptions        5
  24.  
  25.  
  26.  
  27. Abstract
  28.  
  29. This technical report details my discoveries about NewtonScript bytecode. 
  30.  It is not an official Apple document and as the information was discovered 
  31. by observation only, it may be neither accurate nor complete.  This document 
  32. is distributed in the hope that it will be useful, but without any warranty; 
  33. without even the implied warranty of merchantability or fitness for a particular 
  34. purpose.
  35.  
  36. The discoveries detailed in this technical report cover how compiled NewtonScript 
  37. is represented on the Apple MessagePad platform, how values are encoded, 
  38. the general format of bytecode, and the behaviour of individual bytecodes.
  39.  
  40. The author is indebted to Jason Harper for his ViewFrame Demo program, 
  41. which made me realise that bytecode might not be as impenetrable as I first 
  42. thought.  Any omissions or errors in this document are though, entirely 
  43. my responsibility.
  44.  
  45.  
  46.  
  47. Apple and Newton are trademarks of Apple Computer, Inc., registered in 
  48. the United States and other countries.  MessagePad, NewtonScript and Newton 
  49. ToolKit are trademarks of Apple Computer, Inc.  ViewFrame is a trademark 
  50. of Jason Harper. 
  51.  
  52. 1(null)(null)    Background to ByteCode
  53.  
  54. In order to understand fully the description of NewtonScript bytecode given 
  55. in the second section of this report a number of things first need to be 
  56. made clear.
  57.  
  58. 1.1    The Representation of Compiled NewtonScript
  59.  
  60. A compiled NewtonScript function is represented on the MessagePad as a 
  61. frame with the following fixed format:
  62.  
  63. {
  64.     class: 'CodeBlock,
  65.     instructions: <bytecode of type 'instructions>,
  66.     literals: [...],
  67.     argFrame: {
  68.         _nextArgFrame: {}
  69.         _Parent: {},
  70.         _implementor: {},
  71.         ...
  72.         },
  73.     numArgs: <integer>
  74. }
  75.  
  76. D    class is always set to the symbol 'CodeBlock.
  77.  
  78. D    instructions is a block of bytecode bytes, the meaning of which we will 
  79. get to a little later.
  80.  
  81. D    literals is an array of all the literal values used in the NewtonScript 
  82. function (symbols, staticly defined frames, sub<#0106>functions and so 
  83. on).
  84.  
  85. D    numArgs is the number of arguments to the function.
  86.  
  87. D    argFrame consists of three sections:
  88.  
  89. S    The first three items are always the fixed slots _nextArgFrame, _Parent 
  90. and _implementor.
  91.  
  92. S    The next numArgs slots (i.e. possibly none if numArgs is zero) are arguments 
  93. of the function in the order that they appear in the source code.
  94.  
  95. S    Any remaining slots (again possibly none) represent the local variables 
  96. declared within the function.
  97.  
  98. To give a concrete example, here is a short NewtonScript function and the 
  99. frame that represents it:
  100.  
  101. func( foo, bar )                                {
  102. begin                                                    class: 
  103. 'CodeBlock,
  104.     local    fred := '[];                            instructions: 
  105. <instructions>,
  106.                                                             /* 
  107. 18 A5 7D 02 */
  108.     return fred                        
  109.  
  110.                 literals: 
  111. [ '[] ],
  112. end                                                        argFrame: 
  113. {
  114.                                                             _nextArgFrame: 
  115. {},
  116.                                                             _Parent: 
  117. {},
  118.                                                             _implementor: 
  119. {},
  120.                                                             foo: 
  121. NIL,
  122.                                                             bar: 
  123. NIL,
  124.                                                             fred: 
  125. NIL
  126.                                                         },
  127.                                                         numArgs: 
  128. 2
  129.                                                     }
  130.  
  131. 1.2    How Values are Encoded in NewtonScript
  132.  
  133. A knowledge of how NewtonScript encodes values is useful for understanding 
  134. some of the bytecodes.  Certain simple values such as integers, and the 
  135. constants True and Nil are encoded as immediate values.  More complex values 
  136. such as floats, icons, frames and arrays are encoded as separate data blocks 
  137. and then referred to via a pointer.
  138.  
  139. NewtonScript has a uniform way of encoding both the simple values and the 
  140. pointers to more complex values within a 32 bit field.  It achieves this 
  141. by using the lowest two bits of the field as a type identifier.  What the 
  142. value means for each of the four possible types is as follows:
  143.  
  144. 00    The field represents a signed integer in the range -229 to +229-1. 
  145.  i.e. if the low two bits of the 32 bit value are zero, the integer value 
  146. that it represents can be obtained by performing value >> 2.
  147.  
  148. 01    The field represents a pointer to a complex structure.  The pointer 
  149. value can be obtained by performing value & 0xFFFFFFFC.
  150.  
  151. 10    The field represents a unique system value.  As far as I'm aware 
  152. the possible values are:
  153.  
  154.     0x00000002    Nil
  155. 0x0000001A    True
  156. 0x000UUUU6    The Unicode character \uUUUU, e.g. the NewtonScript constant
  157.     $A translates to the immediate value 0x00000496.
  158.  
  159. 11    The field represents a magic pointer.  These are the constants 
  160. that are reperesented as @<number> and have names beginning with ROM_ in 
  161. the NTK definitions file.  The number is encoded in the top 30 bits of 
  162. the field.  As an example, ROM_asciishift (@7) is encoded as 0x0000001F, 
  163. i.e. ....000111 11.
  164.  
  165. 2(null)(null)    ByteCode
  166.  
  167. 2.1    The General Format of ByteCode
  168.  
  169. All NewtonScript bytecodes are either one or three bytes long.  If the 
  170. low three bits of the first byte in the sequence are all 1 then the following 
  171. two bytes are also part of the instruction, otherwise it is a single byte 
  172. instruction.  The following are all examples of valid byte codes (shown 
  173. in hexadecimal):
  174.  
  175.     00            73            5F 02 15            37 
  176. 00 10
  177.  
  178. Very often (but not always) the low three bits are used as a count value 
  179. and if the required value exceeds 6 then all three bits are set and the 
  180. following two bytes are used instead for the value.  Hence this initially 
  181. rather odd seeming format is actually quite useful for keeping bytecode 
  182. compact.  The use of this count field is explained in more detail below.
  183.  
  184. 2.2    Explanation of the Description of Individual ByteCodes
  185.  
  186. All of the bytecode descriptions given below follow the same format:
  187.  
  188. Octal value    (Hex value) Name
  189.  
  190.     Stack behaviour
  191.  
  192.     Longer description.
  193.  
  194. The bytecodes are given as octal values first, because this makes it easier 
  195. to show the low three bits of the code as a separate digit.  As mentioned 
  196. above, these three bits often act as a count field.  When this is the case, 
  197. the letter `N' will be used instead of a digit and the role played by the 
  198. count field will be explained in the stack behaviour and description sections. 
  199.  Remember that any bytecode listed as xxN can be either one or three bytes 
  200. long!
  201.  
  202. The hex value of the bytecode is also given as tools such as ViewFrame 
  203. tend to show raw data in hex format rather than octal.  In the case of 
  204. bytecodes with a count field, the hex value given will be with the count 
  205. set to zero.
  206.  
  207. Bytecode is executed on a virtual machine that uses a stack of NewtonScript 
  208. values (see section 1.2), hence how each instruction modifies the stack 
  209. important.  The stack behaviour is shown as:
  210.  
  211. {items removed from stack by execution} -> {items placed on stack after 
  212. execution}
  213.  
  214. The items are listed in the order that they are pushed onto the stack, 
  215. i.e. the leftmost is the first item pushed and the rightmost the last. 
  216.  Repetition of items is indicated by braces (...) followed by a repetition 
  217. count.  If an item on the stack must be of a certain type, the description 
  218. says so, otherwise placeholders such as <#007F>X" are used.  References 
  219. to arrays, frames and symbols are indicated by [], {} and ' respectively. 
  220.  An empty stack is indicated by the symbol <#00D8>.
  221.  
  222. 2.3    ByteCode Descriptions
  223.  
  224. 000    (00) pop
  225.  
  226. X -> <#00D8>
  227.  
  228. Removes the top item from the stack.
  229.  
  230. 001    (01) dup
  231.  
  232. X -> X, X
  233.  
  234. Duplicates the top item on the stack.
  235.  
  236. 002    (02) return
  237.  
  238. <#00D8> -> <#00D8>
  239.  
  240. Exits from a routine.  By convention, the top item on the stack is the 
  241. return value of the routine.  It is possible to return from a routine with 
  242. more items on the stack (or none at all), however the current Apple NewtonScript 
  243. compiler ensures that the functions that it produces always leave one and 
  244. only one value on the stack.
  245.  
  246. 003    (03) self
  247.  
  248. <#00D8> -> self
  249.  
  250. Pushes a reference to the frame containing the current function onto the 
  251. stack.  In other words this pushes the value represented by the NewtonScript 
  252. value self.
  253.  
  254. 004    (04) Create closure (?)
  255.  
  256. {CodeBlock} -> {CodeBlock}
  257.  
  258. This bytecode is inserted by the compiler whenever it has just pushed a 
  259. CodeBlock frame either as a parameter to a function call or message send, 
  260. or as the target of a call...with statement.  My guess is that this initialises 
  261. the three reserved fields in the argFrame of the CodeBlock (see 1.1), but 
  262. I haven't yet attempted to verify this.
  263.  
  264. 005    (05) foreach next
  265.  
  266. [iterator] -> <#00D8>
  267.  
  268. Steps to next item in iteration.  See 307 000 021 - foreach for a full 
  269. explanation.
  270.  
  271. 006    (06) foreach complete
  272.  
  273. [iterator] -> Boolean
  274.  
  275. Checks if iteration complete.  See 307 000 021 - foreach for a full explanation.
  276.  
  277. 007    000 007 (07 00 07) End exception handling (?)
  278.  
  279. <#00D8> -> <#00D8>
  280.  
  281. See 31N - onexception for a full explanation.
  282.  
  283. 01N    (08) Apparently unused
  284.  
  285. 02N    (10) Apparently unused
  286.  
  287. 03N    (18) Push literal value
  288.  
  289. <#00D8> -> literal N
  290.  
  291. Pushes the literal which is element N of the literals array of this code 
  292. block onto the stack.
  293.  
  294. 04N    (20) Push immediate value
  295.  
  296. <#00D8> -> N
  297.  
  298. N here is treated as an immediate value as described in section 1.2.  This 
  299. instruction is used to push any immediate value that can be represented 
  300. in 16 (sign extended) bits or less.  Values that require the full 32 bits 
  301. are stored as literals and pushed using 03N.
  302.  
  303. Some examples of the use of this instruction:
  304.  
  305. 20    push 0
  306. 22    push Nil
  307. 23    push @0
  308. 24    push 1
  309. 27 00 1A    push True
  310. 27 02 86    push $(
  311. 27 FF F8    push -2
  312.  
  313. 05N    (28) Call global
  314.  
  315. (Arg)N, 'FunctionSymbol -> <#00D8>
  316.  
  317. N arguments to the function are expected on the stack (pushed in the same 
  318. order that they are listed in the function parameter list), followed by 
  319. a reference to the symbol that represents the name of the function (this 
  320. is stored in the literals array and pushed using 03N).  Although the stack 
  321. description indicates that the instruction itself pushes nothing onto the 
  322. stack, remember that all NewtonScript functions conventionally push a single 
  323. item onto the stack before returning.
  324.  
  325. Example:
  326.  
  327. max( foo, bar ) translates to:
  328.  
  329. 7B    push foo (assuming it to be the first parameter of the function)
  330. 7C    push bar (assuming it to be the second)
  331. 18    push 'max (assuming it to be the first literal in the function)
  332. 2A    Call a global function with two arguments.
  333.  
  334. 06N    (30) Call ... with
  335.  
  336. (Arg)N, {004'd CodeBlock} -> <#00D8>
  337.  
  338. This directly translates the NewtonScript <#007F>call ... with ()"  construct. 
  339.  N arguments to the function are expected on the stack (pushed in the same 
  340. order that they are listed in the function parameter list), followed by 
  341. a reference to a CodeBlock frame that has had the 004 instruction called 
  342. on it (qv).  As before, remember that all NewtonScript functions conventionally 
  343. push a single item onto the stack before returning.
  344.  
  345. Example:
  346.  
  347. call func(foo) return foo with (1) translates to:
  348.  
  349. 24    push 1
  350. 18    push func (assuming it to be the first literal in the containing 
  351. function)
  352.     Note that inline function definitions like this are encoded as 
  353. a
  354.     CodeBlock frame in the literals array of the containing function.
  355. 04    Form a closure for the func (?)
  356. 31    Call ... with passing one argument.
  357.  
  358. 07N    (38) Send message
  359.  
  360. (Arg)N, {Receiver}, 'Message -> <#00D8>
  361.  
  362. This directly translates the NewtonScript <#007F>:" construct.  N arguments 
  363. to the message are expected on the stack (pushed in the same order that 
  364. they are listed in the function parameter list), followed by a reference 
  365. to the receiving frame and then the symbol of the message.  Again, remember 
  366. that all NewtonScript functions conventionally push a single item onto 
  367. the stack before returning.
  368.  
  369. Example:
  370.  
  371. :Open() translates to:
  372.  
  373. 03    push self
  374. 18    push 'Open (assuming it to be the first literal in the function)
  375. 38    Send message with zero parameters.
  376.  
  377. 10N    (40) Conditional send message
  378.  
  379. (Arg)N, {Receiver}, 'Message -> <#00D8> or Nil
  380.  
  381. This directly translates the NewtonScript <#007F>:?" construct.  N arguments 
  382. to the message are expected on the stack (pushed in the same order that 
  383. they are listed in the function parameter list), followed by a reference 
  384. to the receiving frame and then the symbol of the message to be sent if 
  385. the given function exists.  If the function doesn't exist, Nil is placed 
  386. on the stack else it's left up to the function to put something there.
  387.  
  388. Example:
  389.  
  390. child:?DoItIfYouCan() translates to:
  391.  
  392. 7B    push child (assuming it to be the first parameter of the function)
  393. 18    push 'DoItIfYouCan (assuming it to be the first literal in the 
  394. function)
  395. 40    Send message with zero parameters if possible.
  396.  
  397. 11N    (48) Inherited send message
  398.  
  399. (Arg)N, 'Message -> <#00D8>
  400.  
  401. This directly translates the NewtonScript <#007F>inherited:" construct. 
  402.    N arguments to the message are expected on the stack (pushed in the 
  403. same order that they are listed in the function parameter list), followed 
  404. by the symbol of the message.  Again, remember that all NewtonScript functions 
  405. conventionally push a single item onto the stack before returning.
  406.  
  407. Example:
  408.  
  409. inherited:Open() translates to:
  410.  
  411. 18    push 'Open (assuming it to be the first literal in the function)
  412. 48    Send message with zero parameters to inheritance parent.
  413.  
  414. 12N    (50) Conditional inherited send message
  415.  
  416. (Arg)N, 'Message -> <#00D8> or Nil
  417.  
  418. This directly translates the NewtonScript <#007F>inherited:?" construct. 
  419.  N arguments to the message are expected on the stack (pushed in the same 
  420. order that they are listed in the function parameter list), followed by 
  421. the symbol of the message to be sent if the given function exists.  If 
  422. the function doesn't exist, Nil is placed on the stack else it's left up 
  423. to the function to put something there.
  424.  
  425. Example:
  426.  
  427. inherited:?DoItIfYouCan() translates to:
  428.  
  429. 18    push 'DoItIfYouCan (assuming it to be the first literal in the 
  430. function)
  431. 50    Send message with zero parameters to inheritance parent (if possible).
  432.  
  433. 13N    (58) Goto
  434.  
  435. <#00D8> -> <#00D8>
  436.  
  437. This instruction causes execution to pass to location N, where N is the 
  438. offset from the start of the block of bytecode (i.e. gotos are absolute, 
  439. not relative).
  440.  
  441. 14N    (60) Goto if not Nil
  442.  
  443. X -> <#00D8>
  444.  
  445. X is removed from the stack and examined.  If it is Nil, execution continues 
  446. with the next instruction in sequence.  If it is not Nil, execution passes 
  447. to location N where N is the offset from the start of the block of bytecode.
  448.  
  449. 15N    (68) Goto if Nil
  450.  
  451. X -> <#00D8>
  452.  
  453. X is removed from the stack and examined.  If it is not Nil, execution 
  454. continues with the next instruction in sequence.  If it is Nil, execution 
  455. passes to location N where N is the offset from the start of the block 
  456. of bytecode.
  457.  
  458. 16N    (70) Push external variable
  459.  
  460. <#00D8> -> value of external variable named by literal N
  461.  
  462. This bytecode pushes onto the stack the value contained in a variable or 
  463. slot from outside of the function.  The name of the variable to push is 
  464. given by literal N in the function's literals array; this literal should 
  465. be a symbol reference.
  466.  
  467. Example:
  468.  
  469. length( functions ) translates to:
  470.  
  471. 70    push value of functions (assuming 'functions is the first entry 
  472. in
  473.     the literals array of the containing CodeBlock)
  474. C7 00 12    Return the length of functions.
  475.  
  476. 17N    (78) Push local variable
  477.  
  478. <#00D8> -> value of local variable in slot N of argFrame
  479.  
  480. This bytecode pushes onto the stack the value contained in the Nth slot 
  481. of the CodeBlock's argFrame frame.  In other words, this bytecode is commonly 
  482. used to push either the value of an argument to the function or that of 
  483. a local variable.
  484.  
  485. Example:
  486.  
  487. func( foo ) return foo translates to:
  488.  
  489. 73    push value of foo (remember argument slots start after the three 
  490. fixed
  491.     slots in argFrame, hence the index is 3 not 0).
  492. 02    Return
  493.  
  494. 20N    (80) Create frame
  495.  
  496. (SlotValue)N, [frameMap] -> {frame}
  497.  
  498. This bytecode creates a frame given N slot values on the stack plus a frame 
  499. map describing the slots in the frame.  The frame map is an array whose 
  500. first item is Nil and then each subsequent item is a reference to a symbol 
  501. giving the name of the corresponding slot in the frame being created.  
  502. The values are pushed onto the stack in the order of the slot names in 
  503. the frame map.  If this is as clear as mud, maybe the example will help:
  504.  
  505. Example:
  506.  
  507. local fr := { size: 4, count: 7 } translates to:
  508.  
  509. 27 00 10    push 4
  510. 27 00 1C    push 7
  511. 18    push frame map (assuming it to be the first literal in the CodeBlock)
  512.     The frame map is an array thus: [Nil, 'size, 'count]
  513. 82    Create a frame with two slots
  514. A6    Store in fr (assumed to be the 6th slot in argFrame)
  515.  
  516. A final NB.  The frame map array isn't a normal array of class Array.  
  517. Its class is a small integer, whose value seems to be made up from three 
  518. possible flags.  I'm investigating the meaning of these flags at the moment.
  519.  
  520. 21N    (88) Create array
  521.  
  522. (Element)N, 'Class -> [Class: ...]    or
  523. Integer, 'Class -> [Class: ...]    for 8F FF FF
  524.  
  525. This bytecode creates an array given N element values on the stack plus 
  526. a reference to a symbol defining the class of the array.  The class of 
  527. the array is specified in NewtonScript with an initial <#007F><class>:" 
  528. inside the array, e.g.: [stepChildren:].  If no class is specified, then 
  529. the default class of Array is used.
  530.  
  531. In the special case of N being 0xFFFF, the instruction takes a single NewtonScript 
  532. integer from the stack instead of N element values and creates an empty 
  533. array (i.e. each element is Nil) with the given number of elements.
  534.  
  535. Example:
  536.  
  537. local foo := [ 4, 7 ] translates to:
  538.  
  539. 27 00 10    push 4
  540. 27 00 1C    push 7
  541. 18    push 'Array (assuming it to be the first literal in the CodeBlock)
  542. 8A    Create an array with two elements
  543. A5    Store in foo (assumed to be the 5th slot in argFrame)
  544.  
  545. 221    (91) Push slot value
  546.  
  547. {frame}, 'SlotName -> slot value
  548.  
  549. This takes a frame and the name of a slot in that frame and pushes the 
  550. value contained in the slot.  If the slot name is a single name then it 
  551. is represented by a symbol reference.  If the slot name is a path expression 
  552. (e.g. foo.bar) then it is represented by an array of class pathExpr with 
  553. one element per section of the path.  Each element is then a reference 
  554. to the symbol for that part of the path.
  555.  
  556. Example:
  557.  
  558. return self.foo.bar translates to:
  559.  
  560. 03    push self
  561. 18    push '[pathExpr: 'foo, 'bar] (assuming it to be the first literal)
  562. 91    Get slot value
  563. 02    Return
  564.  
  565. 230    (98) Assign to slot
  566.  
  567. {X}, 'SlotName, Y -> <#00D8>
  568.  
  569. This assigns the value Y to the slot SlotName of frame X, i.e. X.SlotName 
  570. := Y.
  571. As with 221 (push slot value) the slot name is represented either by a 
  572. simple symbol reference or a pathExpr array for a complex path expression.
  573.  
  574. 231    (99) Assign to slot and push result
  575.  
  576. {X}, 'SlotName, Y -> Y
  577.  
  578. Identical to 230 except that the value assigned to the slot is also pushed 
  579. onto the stack.
  580.  
  581. 24N    (A0) Assign to local variable
  582.  
  583. X -> <#00D8>
  584.  
  585. Value X is assigned to the Nth slot of the CodeBlock's argFrame frame. 
  586.  In other words, this bytecode is usually used to set the value of a local 
  587. variable.
  588.  
  589. Example:
  590.  
  591. local x := '[] translates to:
  592.  
  593. 18    push '[] (assuming it to be the first literal)
  594. A7 00 10    Assign to x (assuming it to be 16th slot in argFrame)
  595.  
  596. 25N    (A8) Assign to external variable
  597.  
  598. X -> <#00D8>
  599.  
  600. Value X is assigned to a variable or slot from outside of the function. 
  601.  The name of the variable to assign to is given by literal N in the function's 
  602. literals array; this literal should be a symbol reference.
  603.  
  604. 26N    (B0) Increment local variable
  605.  
  606. Increment -> Increment, local variable N + Increment
  607.  
  608. This bytecode adds the given integer increment to the local variable in 
  609. the Nth slot of the CodeBlock's argFrame and the returns both the increment 
  610. and the new value of the local variable.  This instruction is used internally 
  611. as part of the coding of for loops.
  612.  
  613. 27N    (B8) for loop goto
  614.  
  615. Increment, value, limit -> <#00D8>
  616.  
  617. This instruction is placed at the end of a for loop construct.  It takes 
  618. the increment, current value of the counter (after having been incremented 
  619. by 26N) and the limit value of the loop.  If the counter value now exceeds 
  620. the loop limit,  execution continues with the next instruction in sequence. 
  621.  If it does not, execution passes to location N where N is the offset from 
  622. the start of the block of bytecode.  This instruction is used internally 
  623. as part of the coding of for loops.
  624.  
  625. 300    (C0) Add
  626.  
  627. X, Y -> X+Y
  628.  
  629. The 30N bytecode series encodes a number of different low<#0106>level system 
  630. function calls.  Any NewtonScript operator or built<#0106>in function not 
  631. explicitly mentioned here is implemented by using a standard function call 
  632. (bytecode 05N).  This first bytecode of the series implements addition 
  633. (of integers or floats).
  634.  
  635. 301    (C1) Subtract
  636.  
  637. X, Y -> X-Y
  638.  
  639. Subtraction of integers or floats.
  640.  
  641. 302    (C2) Dereference array element
  642.  
  643. [X], Y -> X[Y]
  644.  
  645. This pushes the array element Y of array X.  Y should be an integer.
  646.  
  647. 303    (C3) Assign to array element and push
  648.  
  649. [X], Y, Z -> Z
  650.  
  651. This assignes value Z to the pushes the array element Y of array X i.e. 
  652. X[Y] := Z.  Y should be an integer.
  653.  
  654. 304    (C4) Comparison for equality
  655.  
  656. X, Y -> Boolean (X=Y)
  657.  
  658. This compares X and Y for equality and pushes a Boolean result (True or 
  659. Nil).
  660.  
  661. 305    (C5) Not
  662.  
  663. X -> Boolean (not X)
  664.  
  665. This takes any value X and returns not X.  Not Nil is True, not anything 
  666. else is Nil.
  667.  
  668. 306    (C6) Comparison for inequality
  669.  
  670. X, Y -> Boolean (X<>Y)
  671.  
  672. This compares X and Y for inequality and pushes a Boolean result (True 
  673. or Nil).
  674.  
  675. 307    000 007 (C7 00 07) Multiply
  676.  
  677. X, Y -> X*Y
  678.  
  679. This implements multiplication (of integers or floats).
  680.  
  681. 307    000 010 (C7 00 08) Divide (with float result)
  682.  
  683. X, Y -> Float (X/Y)
  684.  
  685. This implements division (of integers or floats) with a float result, i.e. 
  686. it corresponds to the <#007F>/" operator in NewtonScript.
  687.  
  688. 307    000 011 (C7 00 09) Divide (with integer result)
  689.  
  690. X, Y -> Integer (X div Y)
  691.  
  692. This implements division of integers with an integer result, i.e. it corresponds 
  693. to the <#007F>div" operator in NewtonScript.
  694.  
  695. 307    000 012 (C7 00 0A) Compare less than
  696.  
  697. X, Y -> Boolean (X < Y)
  698.  
  699. This checks if X is less than Y and pushes a Boolean result (True or Nil).
  700.  
  701. 307    000 013 (C7 00 0B) Compare greater than
  702.  
  703. X, Y -> Boolean (X > Y)
  704.  
  705. This checks if X is greater than Y and pushes a Boolean result (True or 
  706. Nil).
  707.  
  708. 307    000 014 (C7 00 0C) Compare greater than or equal
  709.  
  710. X, Y -> Boolean (X >= Y)
  711.  
  712. This checks if X is greater than or equal to Y and pushes a Boolean result 
  713. (True or Nil).
  714.  
  715. 307    000 015 (C7 00 0D) Compare less than or equal
  716.  
  717. X, Y -> Boolean (X <= Y)
  718.  
  719. This checks if X is less than or equal to Y and pushes a Boolean result 
  720. (True or Nil).
  721.  
  722. 307    000 016 (C7 00 0E) Binary and
  723.  
  724. Integer X, integer Y -> Integer band(X,Y)
  725.  
  726. This performs a binary and of the two integers X and Y.
  727.  
  728. 307    000 017 (C7 00 0F) Binary or
  729.  
  730. Integer X, integer Y -> Integer bor(X,Y)
  731.  
  732. This performs a binary or of the two integers X and Y.
  733.  
  734. 307    000 020 (C7 00 10) Binary not
  735.  
  736. Integer X -> Integer bnot(X)
  737.  
  738. This performs a binary not of the integer X.
  739.  
  740. 307    000 021 (C7 00 11) foreach
  741.  
  742. X, Boolean  -> [Iterator]
  743.  
  744. This is the fundamental instruction used to implement all NewtonScript 
  745. foreach loops.  If the Boolean is Nil it begins a normal foreach loop and 
  746. if it is True it begins a foreach deeply loop.  The iterator returned is 
  747. then passed to the other two related instructions 005 (foreach next) and 
  748. 006 (foreach complete).  The iterator itself is an array containing various 
  749. useful state information about what is being iterated over and how far 
  750. the iteration has progressed.
  751.  
  752. 005 (foreach next) takes the iterator and modifies it so that the next 
  753. item in the iteration becomes the current item.  006 (foreach complete) 
  754. checks the state of the iterator and returns True if all items have been 
  755. iterated over and Nil if not.
  756.  
  757. So, a foreach loop is implemented in bytecode as:
  758.  
  759. ??    push thing being iterated over
  760. 27<#0102>00<#0102>1A/22    push True or Nil (for deeply or not)
  761. C7 00 11    Create foreach iterator
  762. A?    Assign it to a local variable.
  763. ...    Perform other initialisation (depends on the loop type)
  764. 5F ?? ??    Goto end of loop check (Y:)
  765. X: ...    Code executed each time round the iteration.
  766. 7?    Push the local variable referencing the iterator
  767. 05    And move to the next thing to be iterated
  768. Y: 7?    Push the iterator again
  769. 06    And check if we've finished iterating
  770. 6F ?? ??    Go round the loop again if not (X:)
  771.  
  772. 307    000 022 (C7 00 12) length
  773.  
  774. X -> Integer length(X)
  775.  
  776. This implements the length function.
  777.  
  778. 307    000 023 (C7 00 13) clone
  779.  
  780. X -> clone(X)
  781.  
  782. This implements the clone function.
  783.  
  784. 307    000 024 (C7 00 14) SetClass
  785.  
  786. X, 'Symbol -> modified X
  787.  
  788. This implements the SetClass function e.g. SetClass( data, 'Binary ).  
  789. X is a complex data structure (frame, array or data block); SetClass sets 
  790. the class of that structure and then returns a reference to the now modified 
  791. structure.
  792.  
  793. 307    000 025 (C7 00 15) AddArraySlot
  794.  
  795. [X], Y -> Y
  796.  
  797. This implements the AddArraySlot function e.g. AddArraySlot( foo, 2 ). 
  798.  Y is added as the last element of the array X.
  799.  
  800. 307    000 026 (C7 00 16) Make string
  801.  
  802. [Array of strings] -> String
  803.  
  804. This takes an array of strings and combines them into a single string. 
  805.  This function is used to implement the NewtonScript operators <#007F>&" 
  806. and <#007F>&&".  <#007F>&&" is currently done by inserting an extra single 
  807. space string into the array of strings to be translated.
  808.  
  809. Example:
  810.  
  811. fred && "me" translates to:
  812.  
  813. 70    push value of fred ('fred is the first literal)
  814. 19 1A 1B    push " " (second), "me" (third) and 'Array (fourth)
  815. 8B    Make an array from 3 parameters and a class symbol
  816. C7 00 16    Make a string from the array
  817.  
  818. 307    000 027 (C7 00 17) Slot exists
  819.  
  820. {X}, 'SlotName -> Boolean (True if X contains the given slot)
  821.  
  822. This implements the exists operator, but only when checking for the existance 
  823. of a slot in a frame (e.g. foo.bar exists).  When checking for the existance 
  824. of a variable, a function call (bytecode 05N) to the function HasVar is 
  825. used instead.
  826.  
  827. 307    000 030 (C7 00 18) ClassOf
  828.  
  829. X -> ClassOf(X)
  830.  
  831. This implements the ClassOf function.
  832.  
  833. 31N     (C8) onexception
  834.  
  835. ('Exception, byte offset)N -> <#00D8>
  836.  
  837. This takes N pairs of an exception symbol and an offset into the bytecode 
  838. to jump to if that exception occurs.  This is used to encode the high level 
  839. try ... onexception construct.  Note that unlike all the goto bytecodes, 
  840. the offset is encoded as a standard NewtonScript integer.  At the end of 
  841. both the normal and the exception code, the bytecode 007 000 007 is executed 
  842. - I guess it clears whatever state was set up.
  843.  
  844. Example:
  845.  
  846. try 1/0 onexception |evt.ex.div0| do nil becomes:
  847.  
  848. 18    push '|evt.ex.div0| (first literal)
  849. 27 00 40    push integer 16
  850. C9    onexception '|evt.ex.div0| goto 16
  851. 24 20    push 1, push 0
  852. C7 00 08    1/0
  853. 07 00 07    End exception block (?)
  854. 5F 00 14    Goto 20 (i.e. the end of this block)
  855. 16: 22    Push Nil
  856. 07 00 07    End exception block (?)
  857.  
  858. 320    - 377 (D0 - FF) Apparently unused
  859.  
  860. (null)
  861.  
  862.